use std::sync::{RwLock, RwLockReadGuard, RwLockWriteGuard};

use parking_lot::{Condvar, Mutex};

use crate::err::AnyResult;

pub trait UnpackableRwLock<T> {
    fn unpack_try_read(&self) -> AnyResult<RwLockReadGuard<'_, T>>;

    fn unpack_try_write(&self) -> AnyResult<RwLockWriteGuard<'_, T>>;
}

impl<T> UnpackableRwLock<T> for RwLock<T> {
    #[inline]
    fn unpack_try_read(&self) -> AnyResult<RwLockReadGuard<'_, T>> {
        self.try_read().map_err(|e| anyhow::anyhow!("{e}"))
    }

    #[inline]
    fn unpack_try_write(&self) -> AnyResult<RwLockWriteGuard<'_, T>> {
        self.try_write().map_err(|e| anyhow::anyhow!("{e}"))
    }
}

#[derive(Debug, Default)]
pub struct Notifier {
    done: Mutex<bool>,
    cv: Condvar,
}

impl Notifier {
    #[inline]
    pub fn wait(&self) {
        let mut done = self.done.lock();
        while !*done {
            self.cv.wait(&mut done);
        }
    }

    #[inline]
    pub fn notify_all(&self) {
        let mut done = self.done.lock();
        *done = true;
        self.cv.notify_all();
    }
}
